#!/bin/bash

#       AUTHOR : liuxu
#       THIS SHELL IS ENVIRONMENT INDEPENDENT

#v1.0   compile and push libs to phone
#       $1 should be file or dir you wish to compile
#       without $1 this sh will compile the current dir
#v1.1   add error code for exit
#       1:     pre-compile error
#       2:     adb error
#       3:     post-compile error, most commonly caused by various compile error
#       4:     adb errors, may be caused by "device not found", not critical
#       5:     compile error
#v1.2   add -t option: touch file before compile. the sh will decide which file to touch, usually the last modified file.
#v2.0   2012-03-28
#       add support for multi-dir/file param
#       add -l option: use the given num as "lunch" command param
#v2.1   2012-04-12
#       add support for "choosecombo" when setting up compile environment
#v2.2   2012-04-19
#       add -d option: enable DEBUG
#v2.3   2012-07-03
#       debug: when LocateAndroidmk() return $PROJECT_PATH, exit sh, or it will run "make" in project root dir.
#v2.4   2012-11-28
#       1. another way to locate $PROJECT_PATH:
#          run "source build/envsetup.sh", if the return value is 0, than the $PROJECT_ROOT dir is located.
#v3.0   2013-01-17
#       this sh is now independent to environment. changes:
#       1. another way to locate $PROJECT_PATH:
#          just follow "gettop": see if "build/core/envsetup.mk" and "Makefile" exists.
#       2. use getopt to process params.
#       3. change the way of process params to let this shell be less dependent to environment.
#       4. when compile many files, print info after compile even if one of the files failed to compile.
#          this is to ensure that we know which modules has already been compiled.
#v3.1   2013-02-01
#       debug: locate wrong project root dir sometimes
#v3.2   2013-02-05
#       add -u option:
#       make update-api after compile
#v3.3   2013-04-15
#       print current time before exit

#====================================
#global variables

#I've exported this var through .bashrc. so just commit the code here. 
#DEFAULT_CONFIG_TAG="Config"

CURRENT_PATH=`pwd`                  #
PROJECT_NAME=                       #
PROJECT_PATH=                       #
LUNCH_NUM=
ERROR_NUM=0                         #mark for error number if an error occure, also can be used as "exit" return number
B_TOUCH_ENABLED="false"             #mark for use touch command before compile
B_ADB_REMOUNT="false"
B_COMPILE_SUCCEED="true"
B_PUSH_TO_PHONE="true"
B_UPDATE_API="false"
DEBUG="false"

SH_DOC=$(dirname $0)"/sh_document"
SH_DOCUMENT=$SH_DOC/document$(date +%m%d)
COM_LIBS_STORE=$SH_DOCUMENT/compiled_store  #used to store compiled file path
TMP_DIR=/tmp/compile_and_push_info          #temp file to store mmm output info

#this array should follow the below format:
#src_file:::compiled_lib:::phone_dir
declare -a MODULE_ARR               #modules generated by compile
MODULE_ARR_LENGTH=${#MODULE_ARR[*]}

#this array should follow the below format:
#src_file:::mk_path
declare -a SRC_ARR                  #src file or dir
SRC_ARR_LENGTH=${#SRC_ARR[*]}

#this array is used to cache duplicated src file
#if two src_file have the same mk_path, one of them is marked as duplicated
#element should be path based on PROJECT_PATH
declare -a DUPLICATED_SRC_ARR
DUPLICATED_SRC_ARR_LENGTH=${#DUPLICATED_SRC_ARR[*]}

#====================================
#util functions

trap "CLEAR_WORK" EXIT

DEBUG() {
    if [ "$DEBUG" == "true" ]; then
        $@
    fi
}

CLEAR_WORK() {
    if [ -e $TMP_DIR ]; then
        sudo rm -rf $TMP_DIR
    fi

    local current_time="`date +%x`  `date +%T`"
    echo "* Time on exit:  $current_time"
    echo
}

function ShellHelp() {
cat <<EOF

--------------------------------------------------------------------------------
USAGE:
compile_and_push.sh [-t] [-x] [-d] [-u] [-l lunch_number] PATH

OPTIONS:
-t : touch the the newest or the given file before compile
-l : use the given number as 'lunch' arg
-d : enable DEBUG, the debug logs will be print
-x : do not push libs to phone after compile
-u : make update-api after compile

DESCRIPTION:
Compile a module based on the given files and dirs, and then push the module(s) to the phone.
By default, the compiled modules will be pushed to the phone.
This shell only compile files or dirs in the same project path.
Note that the options should always come before params.

RETURN CODE:
When things' not all right, this sh will return ERROR CODE as below:
  1:     pre-compile error
  2:     adb error
  3:     post-compile error, most commonly caused by various compile error
  4:     adb errors, may be caused by 'device not found', not critical
  5:     compile error
  6:     input file in different project dir
--------------------------------------------------------------------------------

EOF
}

#see if $1 is interger or not
#if $2, $3 is presented, see if $1 is inside [$2, $3]
#yield true or false
#if present, $2 and $3 should be interger
function IsInterger() {
    local ret       #return value

    if [[ $1 =~ [0-9]+ ]]; then     #make sure input is interger
        ret="true"
    else
        ret="false"
    fi

    if [ "$ret" == "false" -o $# -eq 1 ]; then
        echo $ret
        return
    fi

    if [[ ( $1 -ge $2 ) && ( $1 -le $3 ) ]]; then      #make sure $n is inside the range
        ret="true"
    else
        ret="false"
    fi

    echo $ret
}

#see if $1 is one of the files below:
# c, cpp, h, java, xml, rc
#yield true or false
#$1 should be a full path of a file
function IsAndroidSrcFile() {
    local ret="false"
    if [ ! -f $1 ]; then
        echo "false"
        return
    fi

    local bn=$(basename $1)
    local suffix=${bn#*.}

    if [ "$suffix" == "c" -o \
         "$suffix" == "cpp" -o \
         "$suffix" == "h" -o \
         "$suffix" == "java" -o \
         "$suffix" == "xml" -o \
         "$suffix" == "rc" ]; then
        ret="true"
    else
        ret="false"
    fi

    echo $ret
}

#locate the nearest Android.mk file in the upper dirs
#$1 should be a full path of a file or dir
#without $1 this function will check current path
#yield the path if found, or "/" if not found
function LocateAndroidmk() {
    local path
    local cur_path=$(pwd)
    local ret_path

    if [ $# -eq 0 ]; then
        path=$(pwd)
    elif [ -f $1 ]; then
        path=$(dirname $1 | xargs readlink -f)
    else
        path=$(readlink -f $1)
    fi

    ret_path=$path
    cd $ret_path > /dev/null
    while true; do
        #DEBUG echo "LocateAndroidmk, path: $path; ret path: $ret_path"
        if [ -f $ret_path/Android.mk ]; then
            break
        elif [ "$ret_path" == "/" ]; then
            echo "/"
            return
        fi
        cd ..
        ret_path=$(pwd)
    done

    cd $cur_path > /dev/null
    echo $ret_path
}

#locate project root dir
#$1 should be a full path of a file or dir
#without $1 this function will check current path
#yield the path if found, or "/" if not found
function LocateProjectRoot() {
    local path
    local cur_path=$(pwd)
    local tmp_path
    local prj_path
    
    if [ $# -eq 0 ]; then
        path=$(pwd)
    elif [ -f $1 ]; then
        path=$(dirname $1 | xargs readlink -f)
    else
        path=$(readlink -f $1)
    fi

    tmp_path=$path
    cd $tmp_path > /dev/null
    while true; do
        if [ -f build/core/envsetup.mk -a -f Makefile ]; then
            break
        elif [ "$tmp_path" == "/" ]; then
            echo "/"
            return
        fi
        cd ..
        tmp_path=$(pwd)
    done

    cd $cur_path > /dev/null
    prj_path=$tmp_path
    if [ $? -eq 0 ]; then
        echo $prj_path
    else
        echo "/"
    fi
}

function PrintVariableInfo() {
    [ "$DEBUG" == "false" ] && return

    echo "===================================="
    echo "PROJECT_NAME=$PROJECT_NAME"
    echo "PROJECT_PATH=$PROJECT_PATH"
    echo "LUNCH_NUM=$LUNCH_NUM"
    echo "B_TOUCH_ENABLED=$B_TOUCH_ENABLED"
    echo "B_PUSH_TO_PHONE=$B_PUSH_TO_PHONE"
    echo "B_ADB_REMOUNT=$B_ADB_REMOUNT"

    for src in ${SRC_ARR[*]}; do
        echo "SRC_ARR : $src"
    done

    for module in ${MODULE_ARR[*]}; do
        echo "MODULE_ARR : $module"
    done
    echo "===================================="
}

#====================================
#env related functions

#get touch file between two dirs
#only find files in $1 and superior dir of $1, until we reach $2
#$1 and $2 should be full path of a dir
#$1 should be subdir of $2
function PickTouchFile() {
    local ret=""
    if [ ! -d $1 -o ! -d $2 ]; then
        echo $ret
        return
    fi

    local begin_file=$(readlink -f $1)
    local end_file=$(readlink -f $2)

    if [[ "$begin_file" != "$end_file"* && ! $begin_file -ef $end_file ]]; then
        echo $ret
        return
    fi

    local bn; local suffix
    local current_dir=$begin_file
    local end_dir=$(cd $end_file/.. ; pwd)

    while [ ! $end_dir -ef $current_dir ]; do
        DEBUG echo "DEBUG, search in $current_dir"
        cd $current_dir
        local tmp_arr=$(find $current_dir -maxdepth 1 -type f)
        if [ ${#tmp_arr[*]} -eq 0 ]; then
            #no file type in current dir, continue
            continue
        fi
        touch_file_arr=($(find $current_dir -maxdepth 1 -type f | xargs ls -1t | sed '/\/.git\//d; /Android.mk/d' | sed -n '1,10'p))

        if [ "$DEBUG" == "true" ]; then
            for tfa in ${touch_file_arr[*]}; do
                echo "DEBUG, SrcArrAdd, touch_file_arr : $tfa"
            done
        fi

        for fff in ${touch_file_arr[*]}; do
            bn=$(basename $fff)
            suffix=${bn#*.}
            if [ "$suffix" == "c" -o \
                 "$suffix" == "cpp" -o \
                 "$suffix" == "h" -o \
                 "$suffix" == "java" -o \
                 "$suffix" == "xml" -o \
                 "$suffix" == "rc" ]; then
                ret=$fff
                echo $ret
                return
            fi
        done

        current_dir=$(cd .. ; pwd)
    done

    unset touch_file_arr
    echo $ret
    return
}

#add element to SRC_ARR
#src_file:::mk_path
#src_file & mk_path are paths based on $PROJECT_PATH
#$1 should be full path of src_file
function SrcArrAdd() {
    DEBUG echo "+++++++++++++++++++++++++++"
    DEBUG echo "DEBUG, SrcArrAdd, \$1=$1"
    if [ ! -e $1 ]; then
        echo
        echo "* SrcArrAdd, $1 does not exist. should be full path of a dir or file."
        return 1
    fi

    local mk_path=$(LocateAndroidmk $1)
    DEBUG echo "DEBUG, SrcArrAdd, mk_path=$mk_path"
    
    if [ "$mk_path" == "/" ]; then
        echo
        echo "* SrcArrAdd, could not locate a validate Android.mk for the below path, pls check."
        echo $1
        echo
        ERROR_NUM=1
        exit $ERROR_NUM
    fi
    
    local touch_file
    #touch the newest file in $1
    #if no file exist, touch the newest file in mk_path
    if [ "$B_TOUCH_ENABLED" == "true" ]; then
        if [ -f $1 ]; then
            touch_file=$1
        else
            #cache an arr of the 10 newest files
            #so that if the first newest file could not be used as touch file, use the second, etc.
            touch_file=$(PickTouchFile $1 $mk_path)
            #exit the shell here if DEBUG and TOUCH is enabled, or else it will bring more unnecessary errors
            DEBUG exit $ERROR_NUM
        fi

        DEBUG echo "DEBUG, SrcArrAdd, for $1, touch_file=$touch_file"
        if [ -f $touch_file ]; then
            touch $touch_file
        else
            echo "* fail to locate a proper file to touch."
            echo "* possibly cd to a more specified dir (sub dir of current dir) will solve the problem."
            echo "* it is best if you would use a file type as param."
            ERROR_NUM=1
            exit $ERROR_NUM
        fi
    fi

    local param_full_path=$(readlink -f $1)
    local pj_mk_path=$(echo $mk_path | awk -F "$PROJECT_PATH/" '{print $2}')
    local pj_src_file=$(echo $param_full_path | awk -F "$PROJECT_PATH/" '{print $2}')

    SRC_ARR[$SRC_ARR_LENGTH]="$pj_src_file:::$pj_mk_path"
    SRC_ARR_LENGTH=${#SRC_ARR[*]}
    DEBUG echo "+++++++++++++++++++++++++++"
}

#====================================
#compile related functions

#setup compile environment
function SetupEnv() {
    if [ ! -f $PROJECT_PATH/$PROJECT_NAME.$DEFAULT_CONFIG_TAG ]; then
        echo
        echo "* cannot find .config file !!!"
        ERROR_NUM=1
        return $ERROR_NUM
    fi

    cd $PROJECT_PATH > /dev/null
    . $PROJECT_PATH/build/envsetup.sh

    if [ "$LUNCH_NUM" == "" ]; then
        LUNCH_NUM=$(sed -n '/^DEFAULT_LUNCH_NUM/'p $PROJECT_PATH/$PROJECT_NAME.$DEFAULT_CONFIG_TAG | awk -F "=" '{print $2}')
        COMBO=$(sed -n '/^DEFAULT_COMBO/'p $PROJECT_PATH/$PROJECT_NAME.$DEFAULT_CONFIG_TAG | awk -F "=" '{print $2}')
        if [ ! "$LUNCH_NUM" == "" ]; then
            lunch $LUNCH_NUM
        elif [ ! "$COMBO" == "" ]; then
            choosecombo $COMBO
        else
            echo
            echo "* no validate option for 'lunch' command. use -l to specify a lunch number."
            ShellHelp
            ERROR_NUM=1
            return $ERROR_NUM
        fi
    fi
    
    cd - > /dev/null
}

#add element to MODULE_ARR
#src_file:::compiled_lib:::phone_dir
#src_file & compiled_lib are paths based on $PROJECT_PATH
#$1 should be full path of src_file
#$2 should be full path of compiled_lib
function ModuleArrAdd() {
    if [ ! -e $1 ]; then
        echo
        echo "* ModuleArrAdd, $1 does not exist. should be full path a file"
        return 1
    fi

    local pj_src_file=$(echo $1 | awk -F "$PROJECT_PATH/" '{print $2}')
    local pj_compiled_lib=$(echo $2 | awk -F "$PROJECT_PATH/" '{print $2}')

    local product_name=$(echo $pj_compiled_lib | awk -F "/" '{print $4}')
    local file_basename=$(basename $2)
    local phone_dir=$(echo $2 | awk -F "out/target/product/$product_name" '{print $2}' | awk -F "$file_basename" '{print $1}')

    MODULE_ARR[$MODULE_ARR_LENGTH]="$pj_src_file:::$pj_compiled_lib:::$phone_dir"
    MODULE_ARR_LENGTH=${#MODULE_ARR[*]}
}

#compile all elements in SRC_ARR and decipher compile info
#src_file:::compiled_lib:::phone_dir
function DecipherCompileInfo() {
    local mk_dir; local pj_file ;local tmp_file
    [ -d $TMP_DIR ] || mkdir $TMP_DIR
    local compiled_lib_arr
    local uniq_mk_arr
    local uniq_mk_arr_length
    local is_mk_uniq="true"

    for n in ${SRC_ARR[*]}; do
        mk_dir=$(echo $n | awk -F ":::" '{print $2}')
        pj_file=$(echo $n | awk -F ":::" '{print $1}')
        tmp_file=$(basename $PROJECT_PATH/$pj_file)"_compile_info_"$(date +%m%d%H%M%S)

        #duplicate src_file with the same mk_path
        DEBUG echo "DEBUG, mk_dir : $mk_dir ; uniq_mk_arr : ${uniq_mk_arr[*]}"
        for uma in ${uniq_mk_arr[*]}; do
            if [ $PROJECT_PATH/$uma -ef $PROJECT_PATH/$mk_dir ]; then
                is_mk_uniq="false"
                DUPLICATED_SRC_ARR[$DUPLICATED_SRC_ARR_LENGTH]=$pj_file
                DUPLICATED_SRC_ARR_LENGTH=${#DUPLICATED_SRC_ARR[*]}
                break
            fi
        done

        DEBUG echo "DEBUG, DUPLICATED_SRC_ARR : ${DUPLICATED_SRC_ARR[*]}"
        DEBUG echo "is_mk_uniq : $is_mk_uniq"
        if [ "$is_mk_uniq" == "false" ]; then
            is_mk_uniq="true"
            continue
        fi

        #compile
        if [ "$mk_dir" == "" -o "$mk_dir" == "/" ]; then
            echo "* Should not compile in root dir of a project !"
            ERROR_NUM=1
            exit $ERROR_NUM
        fi
        echo "--------------------------------------------------------------------------------"
        echo "compile ....."
        echo "src file  : $pj_file"
        echo "mk path   : $mk_dir"
        echo "--------------------------------------------------------------------------------"
        echo
        cd $PROJECT_PATH/$mk_dir > /dev/null
        #TODO: perhaps we should use "make" instead of such command as "mm"
        mm | tee -a $TMP_DIR/$tmp_file
        if [ "$B_UPDATE_API" == "true" ]; then
            echo
            echo "make update-api"
            echo
            cd $PROJECT_PATH
            make update-api
        fi
        cd - > /dev/null
        echo

        #duplicate src_file with the same mk_path
        uniq_mk_arr[$uniq_mk_arr_length]=$mk_dir
        uniq_mk_arr_length=${#uniq_mk_arr[*]}

        #decipher
        compiled_lib_arr=($(cat $TMP_DIR/$tmp_file | sed -n '/^Install: /p' | awk -F ": " '{print $2}'))

        if [ "$DEBUG" == "true" ]; then
            for cla in ${compiled_lib_arr[*]}; do
                DEBUG echo "DEBUG, decipher libs from compile info: $cla"
            done
        fi

        if [ ${#compiled_lib_arr[*]} -eq 0 ]; then
            B_COMPILE_SUCCEED="false"
            echo "--------------------------------------------------------------------------------"
            echo "* Error occur while compile below file or dir. pls check it."
            echo "$PROJECT_PATH/$pj_file"
            echo
            JustShowInfo
            ERROR_NUM=5
            exit $ERROR_NUM
        fi

        if [ ! -d $SH_DOC ]; then
            mkdir $SH_DOC
        fi

        if [ ! -d $SH_DOCUMENT ]; then
            mkdir $SH_DOCUMENT
        fi

        for m in ${compiled_lib_arr[*]}; do
            DEBUG echo "DEBUG, PROJECT_PATH/pj_file : $PROJECT_PATH/$pj_file"
            DEBUG echo "DEBUG, PROJECT_PATH/m       : $PROJECT_PATH/$m"
            ModuleArrAdd $PROJECT_PATH/$pj_file $PROJECT_PATH/$m
            echo $PROJECT_PATH/$m >> $COM_LIBS_STORE
        done
    done
}

#====================================
#adb related functions

function ReadyADBRemount() {
    [ "$UID" = "0" ] && SUDO= || SUDO=sudo
#    if [ -f $PROJECT_PATH/out/host/linux-x86/bin/adb ]; then
#        ADB="$SUDO $PROJECT_PATH/out/host/linux-x86/bin/adb"
#    else
#        ADB="$SUDO /usr/local/bin/adb"
#    fi
    ADB="$SUDO /usr/local/bin/adb"
    DEBUG echo "ADB: $ADB"

    local adb_info1=$($ADB remount | sed -n '$'p)
    local retry_count=1     #just retry once
    local i=0
    while [ $retry_count -ne $i ]; do
        echo "$adb_info1"
        if [ "$adb_info1" == "remount succeeded" ]; then
            B_ADB_REMOUNT="true"
            return
        else
            echo "* retry remount."
            $ADB kill-server
            $ADB root
            adb_info1=$($ADB remount | sed -n '$'p)
        fi
        let i++
    done

    echo "* cannot remount, please push libs manually."
    ERROR_NUM=4
    return
}

function JustShowInfo() {
    local src_file
    local phone_dir                        #to where we will put the compiled file
    local compiled_lib

    if [ $ERROR_NUM -ne 0 -a $ERROR_NUM -ne 4 ]; then
        echo
        echo "* some problem happened while running this sh. better not push any libs to the phone. pls check. ERROR_NUM=$ERROR_NUM"
        echo
        exit $ERROR_NUM
    fi

    if [ $MODULE_ARR_LENGTH -eq 0 ]; then
        echo
        echo "* No module generated, exit."
        echo
        ERROR_NUM=3
        exit $ERROR_NUM
    fi

    #display duplicated src arr
    echo "--------------------------------------------------------------------------------"
    
    if [ $DUPLICATED_SRC_ARR_LENGTH -ne 0 ]; then
        echo
        for ddd in ${DUPLICATED_SRC_ARR[*]}; do
            echo "* Duplicate Src File : $ddd"
        done
    fi

    for n in ${MODULE_ARR[*]}; do
        src_file=$(echo $n | awk -F ":::" '{print $1}')
        compiled_lib=$(echo $n | awk -F ":::" '{print $2}')
        phone_dir=$(echo $n | awk -F ":::" '{print $3}')

        if [ "$compiled_lib" == "" ]; then
            echo "* no .so or .jar etc. was generated from below file or dir. pls check it."
            echo "$src_file"
            continue
        fi

        echo
        echo "* Project name           : $PROJECT_NAME"
        echo "* Src File or Dir        : $src_file"
        echo "* File Got From Compile  : $compiled_lib"
        echo "* using below command to push to phone: "
        echo "sudo adb push $PROJECT_PATH/$compiled_lib $phone_dir"
        echo
        echo "--------------------------------------------------------------------------------"
    done
}

function PushToPhone() {
    local src_file
    local phone_dir                        #to where we will put the compiled file
    local compiled_lib

    if [ $ERROR_NUM -ne 0 -a $ERROR_NUM -ne 4 ]; then
        echo
        echo "some problem happened while running this sh. better not push any libs to the phone. pls check. ERROR_NUM=$ERROR_NUM"
        echo
        exit $ERROR_NUM
    fi

    if [ $MODULE_ARR_LENGTH -eq 0 ]; then
        echo
        echo "* No module to be pushed, exit."
        echo
        ERROR_NUM=3
        exit $ERROR_NUM
    fi

    #display duplicated src arr
    if [ $DUPLICATED_SRC_ARR_LENGTH -ne 0 ]; then
        echo
        for ddd in ${DUPLICATED_SRC_ARR[*]}; do
            echo "* Duplicate Src File : $ddd"
        done
    fi

    for n in ${MODULE_ARR[*]}; do
        src_file=$(echo $n | awk -F ":::" '{print $1}')
        compiled_lib=$(echo $n | awk -F ":::" '{print $2}')
        phone_dir=$(echo $n | awk -F ":::" '{print $3}')

        if [ "$compiled_lib" == "" ]; then
            echo "* no .so or .jar etc. was generated from below file or dir. pls check it."
            echo "$src_file"
            continue
        fi

        echo
        echo "* Project name           : $PROJECT_NAME"
        echo "* Src File or Dir        : $src_file"
        echo "* File Got From Compile  : $compiled_lib"

        if [ "$B_ADB_REMOUNT" == "false" ]; then
            echo "* adb remount fail. pls push libs manually. using below command: "
            echo "sudo adb push $PROJECT_PATH/$compiled_lib $phone_dir"
            echo
            continue
        else
            echo
            echo "pushing ..."
            echo "$PROJECT_PATH/$compiled_lib  -->  $phone_dir"
            echo
        fi

        if [ -n "$compiled_lib" -a -n "$phone_dir" ]; then
            $ADB push $PROJECT_PATH/$compiled_lib $phone_dir
        else
            echo "* empty string caused by unknown error."
            echo
            ERROR_NUM=3
            return
        fi
    done
}

#====================================
#process args and opts

#process options
function ProcessOptions() {
    while getopts ":txdul:" opt; do
        DEBUG echo "opt: $opt"
        case "$opt" in
            "t")
                B_TOUCH_ENABLED="true"
                ;;
            "x")
                B_PUSH_TO_PHONE="false"
                ;;
            "u")
                B_UPDATE_API="true"
                ;;
            "d")
                DEBUG="true"
                ;;
            "l")
                DEBUG echo "DEBUG, ProcessParam, LUNCH_NUM=$LUNCH_NUM"
                if [ $(IsInterger $OPTARG) == "true" ]; then
                    LUNCH_NUM=$OPTARG
                else
                    echo "* you need to specify a digit value for option -l"
                    ShellHelp
                    ERROR_NUM=1
                    exit $ERROR_NUM
                fi
                ;;
            "?")
                #Unknown option
                echo "* unknown option: $opt"
                ShellHelp
                ERROR_NUM=1
                exit $ERROR_NUM
                ;;
            ":")
                #an option needs a value, which, however, is not presented
                echo "* option $OPTARG needs a value, but it is not presented"
                ShellHelp
                ERROR_NUM=1
                exit $ERROR_NUM
                ;;
            *)
                #unknown error, should not occur
                echo "* unknown error while processing options and params"
                ShellHelp
                ERROR_NUM=1
                exit $ERROR_NUM
                ;;
        esac
    done
    return $OPTIND
}

#process params
function ProcessParams() {
    DEBUG echo "params: $@"
    if [ $# -eq 0 ]; then
        #no params, just print help
        ShellHelp
        #return 1 here to avoid father operation such as "adb reboot"
        exit 1
    fi

    local pj_root
    local pj_name
    for param in $@; do
        #process and store params into array
        if [ -e $param ]; then
            local full_path=$(readlink -f $param)
            pj_root=$(LocateProjectRoot $full_path)
            DEBUG echo "+++++++++++++++++++++++++++"
            DEBUG echo "ProcessParams, param     : $param"
            DEBUG echo "ProcessParams, pj_root   : $pj_root"
            DEBUG echo "+++++++++++++++++++++++++++"
            
            if [ "$pj_root" == "/" ]; then
                echo
                echo "* target dir is not in any project!"
                ShellHelp
                ERROR_NUM=1
                exit $ERROR_NUM
            fi

            if [ "$PROJECT_NAME" == "" ]; then
                PROJECT_NAME=$(basename $pj_root)
                PROJECT_PATH=$pj_root
            else
                if [ ! "$pj_root" == "$PROJECT_PATH" ]; then
                    echo
                    echo "* for now we do not support compile in different projects. pls compile them one by one."
                    ERROR_NUM=6
                    exit $ERROR_NUM
                fi
            fi
            SrcArrAdd $param

        else
            echo "* param does not exist! $param"
            ShellHelp
            ERROR_NUM=1
            exit $ERROR_NUM
        fi
    done
}

#====================================
#main

ProcessOptions "$@"
param_start=$?
ProcessParams "${@:$param_start}"
unset param_start
    
SetupEnv
DEBUG PrintVariableInfo

DecipherCompileInfo

echo
echo "--------------------------------------------------------------------------------"
echo

if [ "$B_PUSH_TO_PHONE" == "true" ]; then
    ReadyADBRemount
    PushToPhone
else
    JustShowInfo
fi

exit $ERROR_NUM

